package com.shenhangye.pushlive.mp4

import android.util.Log
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.coroutineScope
import com.shenhangye.pushlive.mp4.box.BaseBox
import com.shenhangye.pushlive.mp4.box.FreeBox
import com.shenhangye.pushlive.mp4.box.FtypBox
import com.shenhangye.pushlive.mp4.box.MP4Box
import com.shenhangye.pushlive.mp4.box.MdatBox
import com.shenhangye.pushlive.mp4.box.MoovBox
import com.shenhangye.pushlive.mp4.box.NAUL
import com.shenhangye.pushlive.util.FileUtils
import com.shenhangye.pushlive.util.FileUtils.byteArrayToInt
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import java.util.Locale

class Mp4Decoder {

    enum class BOXTYPE {
        FTYP, MEDIUM, LARGE, EXTRA_LARGE
    };


    var mMP4Box= MP4Box()
    var mFtypBox= FtypBox()
    private  val TAG = "Mp4Decoder"
    constructor(path:String,life:Lifecycle){
        life.coroutineScope.launch(Dispatchers.IO) {
//
//            var index=deparse(data,0,mFtypBox)
//            index =deparse(data,index,mFtypBox);
//            Log.e(TAG, "mFtypBox$mFtypBox")
            var data=FileUtils.getBytes(path)
            deparse(data,0)

        }

    }

    fun getType(byteArray: ByteArray,  nowInex: Int):BOXTYPE{
        var type= byteArray.sliceArray(nowInex+4 until nowInex+8)
        if (type.contentEquals(ftyp)){
            return BOXTYPE.FTYP

        }
        return BOXTYPE.FTYP;

    }

    fun findHeadTypeAnd(byteArray: ByteArray,  nowInex: Int):BaseBox{

        var mBaseBox=BaseBox();
        mBaseBox.box_length=byteArrayToInt(byteArray.sliceArray(nowInex until nowInex+4))
        mBaseBox.box_type= String(byteArray.sliceArray(nowInex+4 until nowInex+8))

        return mBaseBox;


    }
    fun freeDeparse(byteArray: ByteArray,size: Int,length: Int):FreeBox{
        var mFreeBox= FreeBox();
        mFreeBox.box_length=length;
        mFreeBox.box_type="free"


        return mFreeBox;
    }

    fun mdatDeparse(byteArray: ByteArray,size: Int,length: Int):MdatBox{
        var mMdatBox= MdatBox();
        mMdatBox.box_length=length;
        mMdatBox.box_type="mdat"


        return mMdatBox;
    }

    fun moovDeparse(byteArray: ByteArray,size: Int,length: Int):MoovBox{
        var mMoovBox= MoovBox()
        mMoovBox.box_length=length
        mMoovBox.box_type="moov"
        var nowPosition=nowInex+8
        while(nowPosition<length+nowInex){
            var mNAUL=NAUL()
            mNAUL.nalu_length=byteArrayToInt(byteArray.sliceArray(nowPosition until nowPosition+8))
            Log.e(TAG,"nalu_length"+ mNAUL.nalu_length)
            nowPosition=+8
            mNAUL.nalu_header=byteArray.sliceArray(nowPosition until nowPosition+1)
            nowPosition=+1
            mNAUL.nalu_data=byteArray.sliceArray(nowPosition until nowPosition+mNAUL.nalu_length-9)
            nowPosition+=mNAUL.nalu_length;
            mMoovBox.mNaulList.add(mNAUL)
        }
        return mMoovBox;
    }
    fun ftypDeparse(byteArray: ByteArray, index: Int, lenght:Int):FtypBox{
        var mFtypBox=FtypBox();
        mFtypBox.box_type="ftyp"
        mFtypBox.box_length=lenght;
        mFtypBox.major_brand=String(byteArray.sliceArray(index+8 until index+12))
        mFtypBox.minor_version=byteArrayToInt(byteArray.sliceArray(index+12 until index+16))
        mFtypBox.compatible_brand=String(byteArray.sliceArray(index+12 until index+16))
        return mFtypBox;
    }
    var nowInex=0;
    private fun deparse(byteArray: ByteArray,  index: Int){
        nowInex=index
        while (nowInex<byteArray.size){
           var mBas= findHeadTypeAnd(byteArray,nowInex);
            when(mBas.box_type){
                "ftyp"->{
                   mMP4Box.mFtypBox= ftypDeparse(byteArray,nowInex,mBas.box_length)
                    Log.e(TAG,mMP4Box.mFtypBox.toString())
                }
                "moov"->{
                    mMP4Box.mMoovBox= moovDeparse(byteArray,nowInex,mBas.box_length)
                    Log.e(TAG,mMP4Box.mMoovBox.toString())
                }
                "mdat"->{
                    mMP4Box.mMdatBox= mdatDeparse(byteArray,nowInex,mBas.box_length)
                    Log.e(TAG,mMP4Box.mMdatBox.toString())
                }
                "free"->{
                    mMP4Box.mFreeBox= freeDeparse(byteArray,nowInex,mBas.box_length)
                    Log.e(TAG,mMP4Box.mFreeBox.toString())
                }
//                    Log.e(TAG,mBas.box_type)
            }
//            Log.e(TAG,"长度"+mBas.box_length)
            nowInex+=mBas.box_length
        }
//        var size= byteArray.sliceArray(nowInex until nowInex+4)
//        nowInex+=4;
//        mFtypBox.box_length=byteArrayToInt(size);
//        var type= byteArray.sliceArray(nowInex until nowInex+4)
//        nowInex+=4;
//
//        if (type.contentEquals(ftyp)){
//            mFtypBox.box_type=BOXTYPE.FTYP.toString()
//            Log.e(TAG,"type"+BOXTYPE.FTYP.toString())
//        }
//
//        var major_brand= byteArray.sliceArray(nowInex until nowInex+4)
//        mFtypBox.major_brand=String(major_brand);
//        nowInex+=4;
//        mFtypBox.minor_version=byteArrayToInt(byteArray.sliceArray(nowInex until nowInex+4))
//        nowInex+=4
//        val compatible_brand= byteArray.sliceArray(nowInex until nowInex+12)
//        mFtypBox.compatible_brand=String(compatible_brand);
//        nowInex+12;
//        return nowInex;
    }




    fun printHexString(b: ByteArray): String {
        var str = ""
        val size = b.size
        for (i in 0 until size) {
            var hex = Integer.toHexString(b[i].toInt() and 0xFF)
            if (hex.length == 1) {
                hex = "0$hex"
            }
            str += hex.uppercase(Locale.getDefault())
        }
        return  str
    }


    private var ftyp=byteArrayOf(0x66,0x74,0x79,0x70)

    private fun findType(byteArray:ByteArray,index:Int):BOXTYPE{

        var type= byteArray.sliceArray(index+4 until index+8)
        Log.e(TAG,type[0].toString()+" "+type[1]+"--"+type[2]+"----"+type[3])
        if (type.contentEquals(ftyp)){
            return BOXTYPE.FTYP;
        }
        return BOXTYPE.FTYP;
    }
}